/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "gpio.h"
#include "tim.h"
#include "usart.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "com.h"
#include "lcd.h"
#include "ui.h"
#include <string.h>

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t log_level = 1;
buzzer_t buzzer = {0};

sub_control_t sub_group[9] = {0};
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void ComExtern_Rx_Callback();
void ComInternal_Rx_Callback();
void ComSubCtrl_Rx_Callback();
void KeyScan_Run();
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void BuzzerTask(void *pvParameters)
{
    buzzer_t *buzzer_p = (buzzer_t *)pvParameters;
    uint8_t repeat;
    for (;;)
    {
        if (xQueueReceive(buzzer_p->queue, &repeat, portMAX_DELAY) == pdPASS)
        {
            while (repeat--)
            {
                Buzzer_Start(buzzer_p->tone, &buzzer_p->state);
                if (buzzer_p->off_time)
                {
                    vTaskDelay(buzzer_p->on_time / portTICK_RATE_MS);
                    Buzzer_Stop(&buzzer_p->state);
                    vTaskDelay(buzzer_p->off_time / portTICK_RATE_MS);
                }
            }
        }
    }
}

void MainTask(void *pvParameters)
{
    TickType_t xLastWakeTime;
    xLastWakeTime = xTaskGetTickCount();
    for (;;)
    {
        HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
        for (uint8_t i = 0; i < SUBCTRL_NUM; i++)
        {
        }
        HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
        vTaskDelayUntil(&xLastWakeTime, 1000 / portTICK_RATE_MS);
    }
}
void ComExternTask(void *pvParameters)
{
    for (;;)
    {
        ComExtern_Run();
    }
}
void ComInternalTask(void *pvParameters)
{
    for (;;)
    {
        ComInternal_Run();
    }
}
void ComSubCtrlTask(void *pvParameters)
{
    for (;;)
    {
        ComSubCtrl_Run();
    }
}
void InitTask(void *pvParameters)
{
    buzzer.queue = xQueueCreate(1, sizeof(uint8_t));

    xTaskCreate(MainTask, "Main", 256, NULL, 2, NULL);
    xTaskCreate(ComExternTask, "ComExtern", 256, NULL, 5, NULL);
    xTaskCreate(ComInternalTask, "ComInternal", 256, NULL, 5, NULL);
    xTaskCreate(ComSubCtrlTask, "ComSubCtrl", 256, NULL, 5, NULL);

    xTaskCreate(BuzzerTask, "Buzzer", 256, &buzzer, 3, NULL);
    LOG("系统初始化完成\n");
    vTaskDelete(NULL);
}
/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{

    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();
    MX_USART2_UART_Init();
    MX_USART3_UART_Init();
    MX_ADC3_Init();
    MX_DAC_Init();
    MX_TIM9_Init();
    MX_TIM13_Init();
    /* USER CODE BEGIN 2 */
    lcd_init();
    lcd_clear(WHITE);

    UI_Background();

    ComExtern_Init(&huart1, ComExtern_Rx_Callback);
    ComInternal_Init(&huart2, ComInternal_Rx_Callback);
    ComSubCtrl_Init(&huart3, ComSubCtrl_Rx_Callback);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    xTaskCreate(InitTask, "InitTask", 128, NULL, 7, NULL);
    vTaskStartScheduler();
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Configure the main internal regulator output voltage
     */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 168;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */
void ComExtern_Rx_Callback()
{
    switch (com_extern.payload[0])
    {
    case 0:
        LOG("接收到数据：%s\n", "qunidays");
        break;
    case 1:
        Buzzer_Run(kToneH1, 300, 100, com_extern.payload[1]);
        break;
    }
    LOG("Receiving the data.\n");
}
void ComInternal_Rx_Callback()
{
}
void ComSubCtrl_Rx_Callback()
{
    switch (com_subctrl.payload[0])
    {
    case SUBCTRL_FRAME_HEADER:
        if (!ADD8_Check(com_subctrl.payload, sizeof(sub_control_t)))
        {
            sub_control_t *sub_p = (sub_control_t *)com_subctrl.payload;
            if ((sub_p->flash.ip[3] > SUBCTRL_BASE_ADDRESS - 1) &&
                (sub_p->flash.ip[3] < SUBCTRL_BASE_ADDRESS + SUBCTRL_NUM))
            {
                memcpy(&sub_group[sub_p->flash.ip[3] - SUBCTRL_BASE_ADDRESS], sub_p, sizeof(sub_control_t));
            }
        }
        break;
    }
}

void Buzzer_Run(buzzer_tone_t tone, uint16_t on_time, uint16_t off_time, uint8_t repeat)
{
    buzzer.tone = tone;
    buzzer.on_time = on_time;
    buzzer.off_time = off_time;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xQueueSendFromISR(buzzer.queue, &repeat, &xHigherPriorityTaskWoken);
}

/* USER CODE END 4 */

/**
 * @brief  Period elapsed callback in non blocking mode
 * @note   This function is called  when TIM14 interrupt took place, inside
 * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
 * a global variable "uwTick" used as application time base.
 * @param  htim : TIM handle
 * @retval None
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    /* USER CODE BEGIN Callback 0 */

    /* USER CODE END Callback 0 */
    if (htim->Instance == TIM14)
    {
        HAL_IncTick();
    }
    /* USER CODE BEGIN Callback 1 */
    if (htim->Instance == TIM13)
    {
        KeyScan_Run();
    }
    /* USER CODE END Callback 1 */
}

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
